#include "Beep.h"

#include "Timer.h"
#include "Tools.h"

typedef enum BeepType BeepType;
enum BeepType
{
        BEEP_TYPE_NONE,
        BEEP_TYPE_ONCE,
        BEEP_TYPE_TWICE,
        BEEP_TYPE_SUSTAIN,
};

struct _Beep
{
        Timer         parent_instance;
        GPIO_TypeDef *gpio;
        BeepType      b_type;
        uint16_t      pin;
        uint8_t       b_times;
};

static bool is_inited = false;
static Beep global_beep;

static void
beep_timer_cb(Beep *self)
{
        if (self->b_times == 0) {
                self->b_times += 1;
                return;
        }

        if (self->b_type == BEEP_TYPE_ONCE) {
                GPIO_ResetBits(self->gpio, self->pin);
                timer_stop(TIMER(self));
                self->b_times = 0;
                return;
        }

        if (self->b_times % 2 == 0)
                GPIO_SetBits(self->gpio, self->pin);
        else
                GPIO_ResetBits(self->gpio, self->pin);

        if (self->b_type == BEEP_TYPE_TWICE && self->b_times == 3) {
                self->b_times = 0;
                timer_stop(TIMER(self));
                return;
        }

        self->b_times += 1;
}

Beep *
beep_new_from_global(void)
{
        if (is_inited)
                return &global_beep;
        global_beep.gpio    = GPIOC;
        global_beep.pin     = GPIO_Pin_15;
        global_beep.b_times = 0;

        timer_init(TIMER(&global_beep),
                   OBJECT_IRQ_HANDLER(beep_timer_cb),
                   7200,
                   5000);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
        GPIO_InitTypeDef gpio = {.GPIO_Mode  = GPIO_Mode_Out_PP,
                                 .GPIO_Pin   = global_beep.pin,
                                 .GPIO_Speed = GPIO_Speed_50MHz};
        GPIO_Init(global_beep.gpio, &gpio);
        is_inited = true;
        return &global_beep;
}

void
beep_start(Beep *self)
{
        /* 没写错，需要长蜂鸣时必须关闭间断鸣叫的时钟 */
        timer_stop(TIMER(self));
        GPIO_SetBits(self->gpio, self->pin);
}

void
beep_stop(Beep *self)
{
        timer_stop(TIMER(self));
        GPIO_ResetBits(self->gpio, self->pin);
}

void
beep_suddenly_once(Beep *self)
{
        self->b_type = BEEP_TYPE_ONCE;
        GPIO_SetBits(self->gpio, self->pin);
        // 此处必须先停止时钟，保证不触发钩子函数，再置 b_times 为 0
        timer_stop(TIMER(self));
        timer_set_psc_arr(TIMER(self), 7200, 100);
        self->b_times = 0;
        timer_start(TIMER(self));
}

void
beep_short_once(Beep *self)
{
        self->b_type = BEEP_TYPE_ONCE;
        GPIO_SetBits(self->gpio, self->pin);
        timer_stop(TIMER(self));
        timer_set_psc_arr(TIMER(self), 7200, 1000);
        self->b_times = 0;
        timer_start(TIMER(self));
}

void
beep_short_twice(Beep *self)
{
        self->b_type = BEEP_TYPE_TWICE;
        GPIO_SetBits(self->gpio, self->pin);
        timer_stop(TIMER(self));
        timer_set_psc_arr(TIMER(self), 7200, 1000);
        self->b_times = 0;
        timer_start(TIMER(self));
}

void beep_long_once(Beep *self)
{
        self->b_type = BEEP_TYPE_ONCE;
        GPIO_SetBits(self->gpio, self->pin);
        timer_stop(TIMER(self));
        timer_set_psc_arr(TIMER(self), 7200, 10000);
        self->b_times = 0;
        timer_start(TIMER(self));
}

void
beep_sustain_short(Beep *self)
{
        self->b_type = BEEP_TYPE_SUSTAIN;
        GPIO_SetBits(self->gpio, self->pin);
        timer_stop(TIMER(self));
        timer_set_psc_arr(TIMER(self), 7200, 1000);
        self->b_times = 0;
        timer_start(TIMER(self));
}

void
beep_binary_print(const Beep *self, unsigned char byte)
{
        uint8_t flag = 0x80;
        for (char i = 0; i < 5; ++i) {
                GPIO_SetBits(self->gpio, self->pin);
                delay_ms(30);
                GPIO_ResetBits(self->gpio, self->pin);
                delay_ms(30);
        }
        delay_ms(600);
        for (char i = 0; i < 8; ++i) {
                GPIO_SetBits(self->gpio, self->pin);
                if (flag & byte) {
                        delay_ms(300);
                        GPIO_ResetBits(self->gpio, self->pin);
                } else {
                        delay_ms(15);
                        GPIO_ResetBits(self->gpio, self->pin);
                        delay_ms(100);
                }
                if (i == 3)
                        delay_ms(300);
                delay_ms(200);
                flag >>= 1;
        }
}

void
beep_binaries_print(Beep *self, const unsigned char *bytes)
{
        for (short i = 0; bytes[i] != '\0'; ++i)
                beep_binary_print(self, bytes[i]);
}
